#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "log.hpp"

Log log;
using func = function<string(char*)> ;
class udpserver
{
public:
    void init()
    {
        // 创建udp server
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            log(Fatal, "server create fail:%d", sockfd_);
            exit(1);
        }
        log(Debug, "server create success:%d", sockfd_);
        // bind socked
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);                  // 转化成网络字节序
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将ip转化成数字，再将数字转化为网络字节序
        if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log(Fatal, "server bind fail:%d\n", sockfd_);
            exit(2);
        }
        log(Debug, "server bind success:%d\n", sockfd_);
    }

    void run(func fun)
    {
        char buf[1024] = {0};
        while (1)
        {
            struct sockaddr_in client; // 客户端的信息
            socklen_t len = sizeof(client);
            // 收数据
            ssize_t n = recvfrom(sockfd_, buf, sizeof(buf), 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                log(Warning, "receice fail, errno:%d, errno string:%s\n", errno, strerror(errno));
                continue;
            }
            buf[n] = 0;
            cout << "server get:" << buf << endl;
            // 处理数据,通过传递的函数实现数据处理的和网络通信解耦
            string ret = fun(buf);
            
            // 发送数据
            n = sendto(sockfd_, ret.c_str(), ret.size(), 0, (struct sockaddr *)&client, len);
            if (n < 0)
            {
                log(Warning, "send fail, errno:%d, errno string:%s\n", errno, strerror(errno));
                continue;
            }
        }
    }
    udpserver(uint16_t port = 8888, string ip = "0.0.0.0")
        : port_(port), ip_(ip)
    {
    }
    ~udpserver()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }

private:
    int sockfd_;
    uint16_t port_;
    string ip_;
};